
/*
* NIST Data Probe Class Library
* clprobe-ui/stepentdescriptor.cc
* April 1997
* David Sauder

* Development of this software was funded by the United States Government,
* and is not subject to copyright.
*/

/* $Id: stepentdescriptor.cc,v 3.0.1.4 1997/11/05 23:01:12 sauderd DP3.1 $ */

#ifdef __O3DB__
#include <OpenOODB.h>
#endif
#include <stdlib.h>
#include <stdio.h>

#include <stepentdescriptor.h>
#include <Str.h>

/*
// in order to include xcanvas.h you will need to have a -I option 
// for /usr/local/include because <X11/Xlib.h> from /usr/local/include/
// gets included from InterViews/include/IV-X11/Xlib.h
#include <IV-X11/xcanvas.h>
#include <InterViews/window.h>
// xcanvas.h and window.h were included so I could write the 
// function IsMapped()
*/
#include <InterViews/canvas.h>
#include <InterViews/window.h>

#include <IV-2_6/InterViews/adjuster.h>
#include <IV-2_6/InterViews/border.h>
#include <IV-2_6/InterViews/defs.h>
#include <IV-2_6/InterViews/frame.h>
#include <IV-2_6/InterViews/glue.h>
#include <IV-2_6/InterViews/interactor.h>
#include <IV-2_6/InterViews/scroller.h>
#include <IV-2_6/InterViews/world.h>
#include <mymessage.h>

#include <scl_hash.h>
#include <probe.h>

extern struct Hash_Table *EntityDictionary;
extern struct Hash_Table *TypeDictionary;

extern Probe *dp;

/*
StepEntityDescriptor *GetStepEntityDescriptor(char *e)
{

//    EntityDescriptor & entDesc = 
//	(EntityDescriptor *)HASHfind(EntityDictionary, StrToUpper(e));
//    return new StepEntityDescriptor(entDesc);
}
*/

/*
Interactor *InsertInteractor (Interactor * i, Interactor * i2, Alignment align)
{
    extern World* dp_world;

    Frame* framedInteractor = new Frame(i, 2);
    Coord x, y;

//    if(i2->IsMapped()){
	i2->Align(BottomCenter, i->GetShape()->width, i->GetShape()->height, x, y);
	i2->GetRelative(x, y, dp_world);
	dp_world->InsertTransient(framedInteractor, i2, x, y, align);
//    } else {
//	x = y = 0;
//	dp_world->InsertTransient(framedInteractor, i2, x, y, align);
//    }
    return(framedInteractor);
}

	//////////////////////////////////

*/
void RemoveInteractor (Interactor* i, Interactor *i2)
{
    Frame* framedInteractor = (Frame*) i->Parent();

    i2->GetWorld()->Remove(framedInteractor);
    framedInteractor->Remove(i);
    delete framedInteractor;
}

//////////////////////////////////////////////////////////////////////////

Interactor* AddRightScroller (Interactor* grid)
{
  return new HBox (
              new MarginFrame (grid, 10),
              new VBorder,
              new VBox (
                   new UpMover (grid, 1),
                   new HBorder,
                   new VScroller (grid),
                   new HBorder,
                   new DownMover (grid, 1)
              )
         );
}

EntityDescriptorBlock::EntityDescriptorBlock (const EntityDescriptor *e, 
					     int maxAttrLen, int maxSubtypeLen)
{
    Init(e, 0, maxAttrLen, maxSubtypeLen);
    MonoScene::Insert(Body());
}

EntityDescriptorBlock::EntityDescriptorBlock (const EntityDescriptor *e, 
					     ButtonState *typeMessage,
					     int maxAttrLen, int maxSubtypeLen)
{
    Init (e, typeMessage, maxAttrLen, maxSubtypeLen);
    MonoScene::Insert(Body());
}

void EntityDescriptorBlock::Init(const EntityDescriptor *e, ButtonState *typeMessage,
				 int maxAttrLen, int maxSubtypeLen)
{
      //////////////////////////////////////////////
      // initialize the member variables
      //////////////////////////////////////////////
    ed = e;
    typeMsg = typeMessage;
    name = new BoldMessage((const char *)(ed->Name()));
    
    attrBS = new ButtonState(0);
    attrBS->Attach(this);
    attrList = &( ((EntityDescriptor *)ed)->ExplicitAttr());

    subtypeBS = new ButtonState;
    subtypeBS->Attach(this);
    subtypeList = &( ((EntityDescriptor *)ed)->Subtypes());

    // lastCloseVal needs to be set the same as the ButtonState's orig. value
    lastCloseVal = 2;
    openCloseBS = new ButtonState(2);
    openCloseBS->Attach(this);
    openCloseBut = new CheckBox("collapse", openCloseBS, 1, 2);

      //////////////////////////////////////////////
      // find out how many attrs there are
      //////////////////////////////////////////////
    int attrCount = attrList->EntryCount();
    if(attrCount < 2) attrCount = 2;

      //////////////////////////////////////////////
      // find out how many subtypes there are
      //////////////////////////////////////////////
    int subtypeCount = subtypeList->EntryCount();

    // determine the height of the box as the highest of the attribute 
    // box or subtype box.
    int entryCount = max(attrCount, subtypeCount);
//////////////////
    
    SCLstring str;
    char endchar;

    attrListBrowser = new StringBrowser(attrBS, entryCount, maxAttrLen);
    AttrDescLinkNode *attrPtr = (AttrDescLinkNode *)attrList->GetHead();
    while( attrPtr != 0)
    {
	endchar = '\0';
	str.set_null();

	const AttrDescriptor *ad = attrPtr->AttrDesc();

	if( ad->Derived() == SCLLOG(LTrue) )
	{
	    str.Append('<');
	    endchar = '>';
	}
/* // for when inverse information is included
	else if( ad->Inverse() == OPLOG(LTrue) )
	{
	    str.Append('(');
	    endchar = ')';
	}
*/
	SCLstring tmp;
	str.Append( ad->AttrExprDefStr(tmp) );
/* // built by hand
	str.Append( ad->Name() );
	str.Append( " : " );
	if( ad->Optional() == OPLOG(LTrue) )
	{
	    str.Append("OPTIONAL ");
	}
	str.Append( attrPtr->AttrDesc()->DomainType()->AttrTypeName() );
*/
	str.Append( endchar );

////////////////////
	attrListBrowser->Append(str.chars());

/*
	attrDefinition = str.chars();
	const char *attrDefPtr = attrDefinition;

	char attrStr[maxAttrLen + 1];
	attrStr[0] = 0;

	strncpy(attrStr, attrDefPtr, maxAttrLen);
	attrStr[maxAttrLen] = 0;
	attrListBrowser->Append(attrStr);
	
	// if the attr def was longer than maxAttrLen continue the definition
	// on lines following starting 5 spaces in.
	attrDefPtr = &attrDefPtr[maxAttrLen];
	while(strlen(attrDefPtr) > 0)
	{
	    memset(attrStr, ' ', 5);
	    memset(attrStr + 5, 0, maxAttrLen - 4);
	    strncat(attrStr, attrDefPtr, maxAttrLen - 5);
	    attrListBrowser->Append(attrStr);
	    attrDefPtr = &attrDefPtr[strlen(attrStr) - 5];
	}
*/

	attrPtr = (AttrDescLinkNode *)attrPtr->NextNode();
    }

//////////////
    subtypeListBrowser = new StringBrowser(subtypeBS, entryCount, maxSubtypeLen);
    EntityDescLinkNode *subtypePtr = 
				(EntityDescLinkNode *)subtypeList->GetHead();
    while( subtypePtr != 0)
    {
	subtypeListBrowser->Append(subtypePtr->EntityDesc()->Name());
	subtypePtr = (EntityDescLinkNode *)subtypePtr->NextNode();
    }
}

Interactor *EntityDescriptorBlock::Body()
{
//    Message *attrsAndSubtypesTitle = new Message("attributes & subtypes");
//    Message *attrsTitle = new Message("attributes");
//    Message *subtypesTitle = new Message("subtypes");
    attrSubtypeBox = new HBox(
		 AddRightScroller(attrListBrowser),
		 new VBorder,
		 AddRightScroller(subtypeListBrowser)
	);
    
    char schemaStr[BUFSIZ];
    schemaStr[0] = '\0';
    const char *schemaStrPtr = ed->OriginatingSchema()->Name();
    if(schemaStrPtr)
	strcpy(schemaStr, schemaStrPtr);
    else
	strcpy(schemaStr, " ");
    MyMessage *schemaMessage = new MyMessage(schemaStr);
    
    bodyBox = new VBox(
	    new HBox(
		     name,
//		     new HGlue(round(.02*inch), round(.02*inch), 0),
//		     attrsAndSubtypesTitle,
		     new HBox(
			      new HGlue(round(.5*inch), round(.5*inch), hfil),
			      schemaMessage,
			      new HGlue(round(.2*inch), round(.2*inch), 0),
			      openCloseBut
			),
		     new HGlue(round(.02*inch), round(.02*inch), 0)
//		     new HGlue(round(.5*inch), round(.5*inch), hfil)
	    ),
	    new HBorder,
	    attrSubtypeBox
	);
    return bodyBox;
}

void EntityDescriptorBlock::Update()
{
    int val = 0;

    // check to see if the subtype ButtonState was set... i.e. 
    // that means an event happened saying the user wanted to pop up a SED
    subtypeBS->GetValue(val);
    if(val) // if the value is set (not zero) 
    {
	subtypeBS->SetValue(0); // reset the value to zero
	if(val == '\r')
	{
	    // get the string the user selected
	    int index = subtypeListBrowser->Selection();
	    char * entity = subtypeListBrowser->String(index);

	    // get the head of the subtype list
	    SingleLinkNode * temp = 
				((EntityDescriptor *)ed)->Subtypes().GetHead();

	    const EntityDescriptor * subtypeED; 
	    if (!temp) // set error -- no subtypes found
		;
	    else 
		subtypeED = ((EntityDescLinkNode *)temp) -> EntityDesc ();
	
	    // find the EntityDescriptor for the entity the user selected
	    while (temp && strcmp (subtypeED -> Name (), entity)) 
		// go thru subtypes until the right one is found
	    {
		temp =  temp -> NextNode ();
		subtypeED =  ((EntityDescLinkNode *)temp) -> EntityDesc ();
	    }

	    if (!temp) // set error -- subtype not found
		;
	    else 
		subtypeED = ((EntityDescLinkNode *)temp) -> EntityDesc ();
	      
	    dp->InsertSED(new StepEntityDescriptor (subtypeED));
	}
    }


    // check to see if the attribute list ButtonState was set... i.e. 
    // that means an event happened saying the user wanted info on an attribute
    attrBS->GetValue(val);
    if(val)
    {
	attrBS->SetValue(0);
	if(val == '\r')
	{
	    int index = attrListBrowser->Selection();

	    AttrDescLinkNode *attrPtr = (AttrDescLinkNode *)
		( ((EntityDescriptor *)ed)->ExplicitAttr().GetHead());

	    char attrStr[BUFSIZ];
	    attrStr[0] = 0;
	    while( attrPtr != 0 && index > 0)
	    {
		index--;
		attrPtr = (AttrDescLinkNode *)attrPtr->NextNode();
	    }
	    SCLstring tmp;
//	    attrStr = attrPtr->AttrDesc()->AttrExprDefStr(tmp);

//	    attrStr = TypeString(attrPtr->AttrDesc());
	    SCLstring tmp2;
	    strncpy(attrStr,
		    attrPtr->AttrDesc()->DomainType()->TypeString(tmp2),
		    BUFSIZ);
	    attrStr[BUFSIZ-1] = 0;

//	    AttrDescriptorList *attrDescList = ed->ExplicitAttr();
//	    AttrDescriptor *attrDesc = attrDescList->GetHead();

//	    char * attrStr = attrListBrowser->String(index);
	    typeMsg->SetValue((char *)attrStr);
	    cout << "Selected attr: '" << attrStr << "'\n";
	}
    }

    openCloseBS->GetValue(val);
//	openCloseBS->SetValue(0);
    if(val != lastCloseVal)
    {
	if(val == 1)
	{
	    bodyBox->Remove(attrSubtypeBox);
	    Change();
	}     
	else if(val == 2)
	{
	    bodyBox->Insert(attrSubtypeBox);
	    bodyBox->Change();
	    Change();
	}     
    }
    lastCloseVal = val;
}

///////////////////////////////////////////////////////////////////////////////

EntityDescBlockNode *
EntityDescBlockList::PrependNode (EntityDescriptorBlock * edb)
{ 
    EntityDescBlockNode *node = (EntityDescBlockNode *) NewNode();
    node->EDBlock(edb);
    if (head) {
	node->next = head;
	head = node;
    }
    else head = tail = node;

    return node;
}    

///////////////////////////////////////////////////////////////////////////////

/*
StepEntityDescriptor::StepEntityDescriptor()
{ 
    edbList = new EntityDescBlockList;
    Scene::Insert(new HBorder(2));
    entDesc = 0;

    closeBS = new ButtonState(0);
    closeBS->Attach(this);
    close = new PushButton("close", closeBS, 1);
    entDesc = ed;

}
*/

char * 
StepEntityDescriptor::LongestAttrInBlock(const EntityDescriptor *entity)
{
    int longestLen = 0;
    static char longestAttrStr[BUFSIZ];
    longestAttrStr[0] = 0;

    const char *attrStr;
    int attrLen;

    if(entity)
    {
	AttrDescLinkNode *attrPtr = 
	    (AttrDescLinkNode *)( ((EntityDescriptor *)entity)->ExplicitAttr().GetHead());
	SCLstring tmp;
	while( attrPtr != 0)
	{
	    attrStr = attrPtr->AttrDesc()->AttrExprDefStr(tmp);
	    attrLen = strlen(attrStr);
	    if( attrPtr->AttrDesc()->Derived() == SCLLOG(LTrue) )
	    {
		attrLen = attrLen + 2;
	    }
/*
	    // for when inverse information is else included
	    else if( attrPtr->AttrDesc()->Inverse() == OPLOG(LTrue) )
	    {
		attrLen = attrLen + 2;
	    }
*/

	    if(attrLen > longestLen)
	    {
		strcpy(longestAttrStr, attrStr);
		longestLen = attrLen;
	    }
	    attrPtr = (AttrDescLinkNode *)attrPtr->NextNode();
	}
    }
    return longestAttrStr;
}

char * 
StepEntityDescriptor::FindLongestAttribute()
{
    int longestLen = 0;
    static char longestAttrStr[BUFSIZ];
    longestAttrStr[0] = 0;

    const EntityDescriptor *ed = entDesc;

    strcpy(longestAttrStr, LongestAttrInBlock(entDesc));
    longestLen = strlen(longestAttrStr);

    char *attrStr = 0;
    int attrLen = 0;

    EntityDescLinkNode *edNode = 
	(EntityDescLinkNode *)( (entDesc->Supertypes()).GetHead() );
    while (edNode)
    {
	ed = edNode->EntityDesc();

	if(ed)
	{
	    attrStr = LongestAttrInBlock(ed);
	    attrLen = strlen(attrStr);
	    if(attrLen > longestLen)
	    {
		strcpy(longestAttrStr, attrStr);
		longestLen = attrLen;
	    }
	    edNode = (EntityDescLinkNode *)( (ed->Supertypes()).GetHead() );
	}
	else
	    edNode = 0;
    }
    return longestAttrStr;
}
//////////////////

char * 
StepEntityDescriptor::LongestSubtNameInBlock(const EntityDescriptor *entity)
{
    int longestLen = 0;
    static char longestSubtypeStr[BUFSIZ];
    longestSubtypeStr[0] = 0;

    const char *subtypeStr;
    int subtypeLen;

    if(entity)
    {
	EntityDescLinkNode *subtypePtr = 
		  (EntityDescLinkNode *)( ((EntityDescriptor *)entity)->Subtypes().GetHead());
	while( subtypePtr != 0)
	{
	    subtypeStr = subtypePtr->EntityDesc()->Name();
	    subtypeLen = strlen(subtypeStr);
	    if(subtypeLen > longestLen)
	    {
		strcpy(longestSubtypeStr, subtypeStr);
		longestLen = subtypeLen;
	    }
	    subtypePtr = (EntityDescLinkNode *)subtypePtr->NextNode();
	}
    }
    return longestSubtypeStr;
}

char * 
StepEntityDescriptor::FindLongestSubtName()
{
    int longestLen = 0;
    static char longestSubtypeStr[BUFSIZ];
    longestSubtypeStr[0] = 0;

    const EntityDescriptor *ed = entDesc;

    strcpy(longestSubtypeStr, LongestSubtNameInBlock(entDesc));
    longestLen = strlen(longestSubtypeStr);

    char *subtypeStr = 0;
    int subtypeLen = 0;

    EntityDescLinkNode *edNode = 
	(EntityDescLinkNode *)( (entDesc->Supertypes()).GetHead() );
    while (edNode)
    {
	ed = edNode->EntityDesc();

	subtypeStr = LongestSubtNameInBlock(ed);
	subtypeLen = strlen(subtypeStr);
	if(subtypeLen > longestLen)
	{
	    strcpy(longestSubtypeStr, subtypeStr);
	    longestLen = subtypeLen;
	}
	edNode = (EntityDescLinkNode *)( ( ((EntityDescriptor *)ed)->Supertypes()).GetHead() );
    }
    return longestSubtypeStr;
}
//////////////////

StepEntityDescriptor::StepEntityDescriptor(const EntityDescriptor *ed)
{ 
    entDesc = ed;
    edbList = new EntityDescBlockList;
    closeBS = new ButtonState(0);
    closeBS->Attach(this);
    close = new PushButton("close", closeBS, 1);

    Scene::Insert(
	new HBox(
		 new HGlue(round(.01*inch),round(.01*inch), 0),
		 close,
		 new HGlue(round(.3*inch),round(.3*inch), 0),
		 new Message("attributes"),
		 new HGlue(round(1*inch),round(1*inch), hfil),
		 new Message("subtypes"),
		 new HGlue(round(.5*inch),round(.5*inch), 0)
		)
	);
    

///////////////
    int maxAttrLen = strlen(FindLongestAttribute());
    int len = 5;
    maxAttrLen = max(maxAttrLen, len);

    int maxSubtypeLen = strlen(FindLongestSubtName());
    maxSubtypeLen = max(maxSubtypeLen, len);

    strDispBS = new ButtonState(0);
    strDispBS->Attach(this);
    strDisp = new StringDisplay(strDispBS, " ");
//////////////
    edbList->PrependNode(new EntityDescriptorBlock(ed, strDispBS, maxAttrLen, 
						   maxSubtypeLen));

    EntityDescLinkNode *parentNode = 
	(EntityDescLinkNode *)( ( ((EntityDescriptor *)ed)->Supertypes()).GetHead() );
    const EntityDescriptor *Parent;
    while (parentNode)
    {
	Parent = parentNode->EntityDesc();

	edbList->PrependNode(new EntityDescriptorBlock(Parent, strDispBS, 
						   maxAttrLen, maxSubtypeLen));
	parentNode =
		 (EntityDescLinkNode *)( ( ((EntityDescriptor *)Parent)->Supertypes()).GetHead() );
    }
    EntityDescBlockNode *edbNode;

    for(edbNode = (EntityDescBlockNode *)edbList->GetHead(); 
	edbNode;
	edbNode = (EntityDescBlockNode *)(edbNode->NextNode()))
    {
	Scene::Insert(new HBorder(2));
	Scene::Insert(edbNode->EDBlock());
    }
    Scene::Insert(new HBorder(2));
    Scene::Insert(
	new MarginFrame(
		new HBox(
			 new Message("Attr. Type: "),
			 new HGlue(round(.05*inch), round(.05*inch), 0),
			 new Frame(strDisp)
			), 2)
		 );
}

/*
StepEntityDescriptor::StepEntityDescriptor(Interactor *i) : (i)
{
    edbList = new EntityDescBlockList;
    Scene::Insert(new HBorder(2));
}
*/

void StepEntityDescriptor::Insert(Interactor *i) 
{
    Scene::Insert(i);
    Scene::Insert(new HBorder(2));
}

void StepEntityDescriptor::Insert(EntityDescriptorBlock *edb) 
{
    edbList->PrependNode(edb);
    
    Scene::Insert(edb);
    Scene::Insert(new HBorder(2));
}
void StepEntityDescriptor::Update()
{
    int val = 0;
    closeBS->GetValue(val);
    closeBS->SetValue(0);
    if (val == 1)
    {
	dp->RemoveSED(this);
//	RemoveInteractor (this, this);
	cout << "close entity display" << "\n";
    }
    char *strVal = 0;
//    strDispBS->GetValue(strVal); // this no longer works with Sun 
				   // C++ => error. Must assign as below DAS
    void * tmpVoidPtr = 0;
    strDispBS->GetValue(tmpVoidPtr); 
    strVal = (char *) tmpVoidPtr;

    strDispBS->SetValue(0);
    if(strVal)
	strDisp->Message(strVal);
}

// boolean i.e. true = 1 and false = 0
boolean StepEntityDescriptor::IsMapped()
{
    return (canvas != nil && canvas->status() == Canvas::mapped);
/* 
    if(canvas)
    {
	// this doesn't work
	int bool = canvas->window()->is_mapped();
	return bool;
    }
    else
	return false;
*/
}
